import { size, time } from './common'
import { total } from './range'
import Axios from 'axios'
import { ref, computed } from 'vue'

const CancelToken = Axios.CancelToken
const axios = Axios.create({
    baseURL: 'http://localhost:3001',
    timeout: 10000
})
export const requestCache = ref({
    id: 0,
    queue: [],
    startTime: 0,
    duration: computed(() =>
        time(total(requestCache.value.queue.map(it => [it.startTime, it.endTime])))
    ),
    size: computed(() =>
        size(requestCache.value.queue.reduce((value, item) => value + item.size, 0))
    ),
    success: computed(() => requestCache.value.queue.filter(it => it.status == 'success').length),
    running: computed(() => requestCache.value.queue.filter(it => it.status == 'running').length),
    error: computed(() => requestCache.value.queue.filter(it => it.status == 'error').length)
})

export function onLoad() {
    requestCache.value.queue.forEach(it => {
        if (it.status == 'running') {
            it.cancelTokenSource.cancel('取消请求')
        }
    })
    requestCache.value.queue.length = 0
    requestCache.value.id = 0
}

axios.interceptors.request.use(
    config => {
        if (requestCache.value.id == 0) {
            requestCache.value.startTime = Date.now()
        }
        if (!config.hasOwnProperty('id')) {
            config.id = requestCache.value.id++
            requestCache.value.queue.push(config)
        }
        let request = requestCache.value.queue.find(it => it.id == config.id)
        request.url = axios.getUri(config)
        request.status = 'running'
        request.startTime = Date.now()
        request.headers['X-Request-Time'] = request.startTime
        request.cancelTokenSource = CancelToken.source()
        request.cancelToken = config.cancelTokenSource.token
        return request
    },
    error => {
        if (Axios.isCancel(error)) {
            console.log('Request canceled:', error.message)
        }
        return Promise.reject(error)
    }
)

axios.interceptors.response.use(
    response => {
        const startRequestTime = response.config.headers['X-Request-Time']
        const endRequestTime = response.headers.get('X-Request-Time')
        const startResponseTime = response.headers.get('X-Response-Time')
        const endResponseTime = Date.now()
        const request = requestCache.value.queue.find(it => it.id == response.config.id)
        request.response = response.data
        if (request) {
            request.endTime = endResponseTime
            request.size = Number(response.headers['content-length'])
            request.duration = {
                clientToServer: endRequestTime - startRequestTime,
                server: startResponseTime - endRequestTime,
                serverToClient: endResponseTime - startResponseTime,
                total: endResponseTime - startRequestTime
            }
            request.endRequestTime = endRequestTime
            if (response.status == 200) {
                const { status, code, msg, data } = response.data
                if (status == 'success') {
                    request.status = 'success'
                } else {
                    request.status = 'error'
                    request.statusText = msg
                }
            } else {
                request.status = 'error'
                request.statusText = response.statusText
            }
        }
        return response
    },
    error => {
        const request = requestCache.value.queue.find(it => it.id == error.config.id)
        if (request) {
            request.endTime = Date.now()
            request.size = 0
            request.status = 'error'
            request.statusText = error.message
            request.duration = {
                total: request.endTime - request.startTime
            }
        }
        return Promise.resolve(error)
    }
)

export async function post(url, data, options = {}) {
    const response = await axios.post(url, data, options)
    if (response.status == 200) {
        const { status, code, msg, data } = response.data
        if (status == 'success') {
            return data
        }
    }
}

export async function get(url, data, options = {}) {
    const opts = {
        method: 'GET',
        url: url,
        params: data
    }
    const response = await axios.get(Object.assign(opts, options))
    if (response.status == 200) {
        const { status, code, msg, data } = response.data
        if (status == 'success') {
            return data
        }
    }
}

export async function request(options) {
    const response = await axios.request(options)
    if (response.status == 200) {
        const { status, code, msg, data } = response.data
        if (status == 'success') {
            return data
        }
    }
}

export function useGet(url, params, options = {}) {
    const { after } = options
    const data = ref()
    const msg = ref()
    async function internalGet() {
        data.value = await get(url, params, options)
        after && after()
    }
    internalGet()
    return { data, msg, refresh: internalGet }
}

export const axiosGet = axios.get
